<?php declare(strict_types=1);
/**
 * This file is part of Swoft.
 *
 * @link     https://swoft.org
 * @document https://swoft.org/docs
 * @contact  group@swoft.org
 * @license  https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

namespace App\Http\Controller\Test;

use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\Http\Server\Annotation\Mapping\RequestMethod;
use Throwable;
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * Class MqController
 * @Controller()
 */
class MqController extends BaseController
{

    /**
     * 1. postman请求接口 -> 控制台查看消息
     * rabbitmq-消费者
     * @RequestMapping("/mq/receive_amqp",method={RequestMethod::GET})
     * @throws Throwable
     */
    public function receive_amqp(){
        //1.创建一个 RabbitMQ 的连接：
        $connection = new AMQPStreamConnection(config('AMQP.host'), config('AMQP.port'), config('AMQP.login'), config('AMQP.password'));
        $channel = $connection->channel();

        //2.设置和生产者相同；我们首先打开一个连接和创建channel，并声明我们要消费的消息队列。注意： 和生产者发送的队列名一致。
        //3.请注意，我们在这里也声明了队列。这是因为我们可能在生产者之前启动消费者，所以我们要确保队列一定存在，然后再尝试从中消费信息。
        $channel->queue_declare('hello', false, false, false, false);
        echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

        //4.在我们将要告诉服务器将队列中的消息传递给我们之前，我们需要定义一个可以接收服务器发送的消息的回调函数。请注意，消息是从服务器异步发送到客户端。
        $callback = function($msg) {
            echo " [x] Received ", $msg->body, "\n";
        };
        $channel->basic_consume('hello', '', false, true, false, false, $callback);
        while(count($channel->callbacks)) {
            $channel->wait();
        }

        //5.关闭channel 和 connection
        $channel->close();
        $connection->close();
    }

    /**
     * 2. postman请求接口
     * rabbitmq-生产者
     * @RequestMapping("/mq/send_amqp",method={RequestMethod::GET})
     * @throws Throwable
     */
    public function send_amqp()
    {
        //1.创建一个 RabbitMQ 的连接：
        $connection = new AMQPStreamConnection(config('AMQP.host'), config('AMQP.port'), config('AMQP.login'), config('AMQP.password'));
        $channel = $connection->channel();

        //2.新建一个 channel, 这是大部分用于完成任务的API所在的地方
        $channel->queue_declare('hello', false, false, false, false);
        $msg = new AMQPMessage('你好，世界!');
        $channel->basic_publish($msg, '', 'hello');
        echo " [x] Sent 'Hello World!'\n";

        //3.关闭channel 和 connection
        $channel->close();
        $connection->close();
    }

    /**
     * 扇出交换机原理：“无路由交换机”，说白了就是，使用这个交换机不需要routingkey绑定，和路由没有关系，它是直接绑定到队列的。
     * 1）启动消费者
     * 2）生产者发送消息
     * 3）消费者收到相同消息
     * rabbitmq-扇出交换机MqConsumerController
     * @RequestMapping("/mq/fanout",method={RequestMethod::GET})
     * @throws Throwable
     */
    public function fanout()
    {
        $producer = new MqProducerController();//生产者
        $data = [
            'time'=>time(),
            'title'=> 'fanout->'.rand(1,100),
        ];
        return $producer->fanout($data);
    }

    /**
     * 主题交换机原理：
     *  1.假如你想在淘宝上买一双运动鞋，那么你是不是会在搜索框中搜“XXX运动鞋”，这个时候系统将会模糊匹配的所有符合要求的运动鞋，然后展示给你。
        2.所谓“主题路由匹配交换机”也是这样一个道理，但是使用时也有一定的规则。
     * rabbitmq-主题交换机
     * @RequestMapping("/mq/topic",method={RequestMethod::GET})
     * @throws Throwable
     */
    public function topic()
    {
        $producer = new MqProducerController();//生产者
        $data = [
            'time'=>time(),
            'title'=> 'topic->'.rand(1,100),
        ];
        return $producer->topic($data); //指向topic主题
    }
}
